package com.eblacorp.archive.security.ldap.dao;

import java.util.Iterator;
import java.util.List;

import javax.naming.directory.BasicAttribute;
import javax.naming.directory.DirContext;
import javax.naming.directory.ModificationItem;

import org.springframework.ldap.core.ContextMapper;
import org.springframework.ldap.core.DirContextAdapter;
import org.springframework.ldap.core.DirContextOperations;
import org.springframework.ldap.core.DistinguishedName;
import org.springframework.ldap.core.LdapOperations;
import org.springframework.ldap.filter.AndFilter;
import org.springframework.ldap.filter.EqualsFilter;
import org.springframework.ldap.filter.WhitespaceWildcardsFilter;

import com.eblacorp.archive.security.ldap.GroupContextMapper;
import com.eblacorp.archive.security.ldap.model.Group;
import com.eblacorp.archive.security.ldap.model.SearchCriteria;
/**
 * @author Mahmoud.Ezzat
 * 
 */
public class GroupDaoImpl implements GroupDao {

	private static final String SEARCH_BASE = "OU=ARCH_USERS_OU,DC=PD,DC=LOCAL";
	
    /**
     * The template object that performs all data access work.
     */
    LdapOperations ldapOperations;

    DistinguishedName buildDn(Group group) {
        DistinguishedName dn = new DistinguishedName();
        dn.add("ou", "groups");
        dn.add("cn", group.getName());
        return dn;
    }

    DirContextOperations setAttributes(DirContextOperations adapter, Group group) {
        adapter.setAttributeValues("objectclass", new String[] { "top",
                "group" });
        adapter.setAttributeValue("cn", group.getName());
        if (group.getMembers() != null && group.getMembers().size() > 0) {
            adapter.setAttributeValues("uniqueMember", group.getMembers()
                    .toArray(new String[0]));
        }
        return adapter;
    }

    ContextMapper getContextMapper() {
        return new GroupContextMapper();
    }

    /*
     * @see org.springframework.ldap.samples.person.dao.GroupDao#create(org.springframework.ldap.samples.person.domain.Group)
     */
    public void create(Group group) {
        ldapOperations.bind(buildDn(group), setAttributes(
                new DirContextAdapter(), group), null);
    }

    /*
     * @see org.springframework.ldap.samples.person.dao.GroupDao#delete(org.springframework.ldap.samples.person.domain.Group)
     */
    public void delete(Group group) {
        ldapOperations.unbind(buildDn(group));
    }

    /*
     * @see org.springframework.ldap.samples.person.dao.GroupDao#find(org.springframework.ldap.samples.person.domain.SearchCriteria)
     */
    public List find(SearchCriteria criteria) {
        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectclass", "group"));
        filter.and(new WhitespaceWildcardsFilter("cn", criteria.getName()));
        return ldapOperations.search(SEARCH_BASE, filter
                .encode(), getContextMapper());
    }

    /*
     * @see org.springframework.ldap.samples.person.dao.GroupDao#findAll()
     */
    public List findAll() {
        EqualsFilter filter = new EqualsFilter("objectclass",
                "group");
        return ldapOperations.search(SEARCH_BASE, filter
                .encode(), getContextMapper());
    }

    /*
     * @see org.springframework.ldap.samples.person.dao.GroupDao#findByPrimaryKey(java.lang.String)
     */
    public Group findByPrimaryKey(String name) {
        DistinguishedName dn = new DistinguishedName("ou=groups");
        dn.add("cn", name);
        return (Group) ldapOperations.lookup(dn, getContextMapper());
    }

    /*
     * @see org.springframework.ldap.samples.person.dao.GroupDao#update(org.springframework.ldap.samples.person.domain.Group)
     */
    public void update(Group group) {
        DistinguishedName dn = buildDn(group);
        DirContextOperations adapter = (DirContextOperations) ldapOperations
                .lookup(dn);
        adapter = setAttributes(adapter, group);
        ldapOperations.modifyAttributes(dn, adapter.getModificationItems());
    }

    public void setLdapOperations(LdapOperations ldapOperations) {
        this.ldapOperations = ldapOperations;
    }

    public void updateMemberDn(String originalDn, String newDn) {
        BasicAttribute removeAttribute = new BasicAttribute("uniqueMember",
                originalDn);
        BasicAttribute addAttribute = new BasicAttribute("uniqueMember",
                newDn);

        ModificationItem[] modificationItems = new ModificationItem[2];
        modificationItems[0] = new ModificationItem(
                DirContext.REMOVE_ATTRIBUTE, removeAttribute);
        modificationItems[0] = new ModificationItem(DirContext.ADD_ATTRIBUTE,
                addAttribute);

        AndFilter filter = new AndFilter();
        filter.and(new EqualsFilter("objectclass", "group"));
        filter.and(new EqualsFilter("uniqueMember", originalDn));

        List list = ldapOperations.search(SEARCH_BASE, filter
                .encode(), new ContextMapper() {
            public Object mapFromContext(Object ctx) {
                DirContextAdapter adapter = (DirContextAdapter) ctx;
                return adapter.getNameInNamespace();
            }
        });

        for (Iterator iter = list.iterator(); iter.hasNext();) {
            String dn = (String) iter.next();
            ldapOperations.modifyAttributes(dn, modificationItems);
        }
    }
}
